package javaDemo.demo.day_01_SaleTicket;

/**
 *【笔记】：
 * 1、在高内聚低耦合的前提下，线程   操作  资源类！
 *【理解】：
 * 1、线程操作资源类！
 * 2、资源类将对外暴露的方法，紧紧地放在资源类的内部！--高内聚
 * 3、资源类与调用的线程之间是没有任何关系的！--低耦合
 */

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Description 卖票多线程的主启动类--原始版：三个人  卖出30张票
 * @Author
 * @Date 2020/10/25 10:13
 * @Version 1.0
 */
public class SaleTicketMain {

    public static void main(String[] args) {

        Ticket ticket = new Ticket();

        //不使用匿名内部类，使用 lambda 表达式简化代码
        new Thread(()->{ for (int i = 0; i <=30 ; i++) ticket.saleTicket(); },"线程A").start();
        new Thread(()->{ for (int i = 0; i <=30 ; i++) ticket.saleTicket(); },"线程B").start();
        new Thread(()->{ for (int i = 0; i <=30 ; i++) ticket.saleTicket(); },"线程C").start();

        //TODO 为什么匿名实现的 Thread ，可以直接访问到 ticket 对象，并且三个线程都访问的是同一个 ticket 对象？
        /*new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <= 30 ; i++) {
                    ticket.saleTicket();
                }
            }
        },"线程A").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <= 30 ; i++) {
                    ticket.saleTicket();
                }
            }
        },"线程B").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <= 30 ; i++) {
                    ticket.saleTicket();
                }
            }
        },"线程C").start();*/
    }
}

//资源类
class Ticket{

    //定义初始票数
    private int ticketNumber = 30;

    //使用 juc 中的工具类
    private Lock lock = new ReentrantLock();

    //对外暴露给线程的方法，定义在资源类里面--使用 juc 中的工具类保证并发安全
    public void saleTicket(){
        lock.lock();
        try {
            if(ticketNumber>0){
                System.out.println(Thread.currentThread().getName() + "\t卖票：" + ticketNumber-- +"\t还剩下：" + ticketNumber);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    //对外暴露给线程的方法，定义在资源类里面--加上synchronize保证并发安全
    /*public synchronized void saleTicket(){
        if(ticketNumber>0){
            System.out.println(Thread.currentThread().getName() + "\t卖票：" + ticketNumber-- +"\t还剩下：" + ticketNumber);
        }else {
            System.out.println("票已卖完！");
        }
    }*/

}
